package service;

import entity.Node;
import entity.NodeType;
import org.neo4j.driver.*;
import org.neo4j.driver.Record;

import java.util.LinkedList;

public class NodeService {
    private final Session session;

    public NodeService(Session session) {
        this.session = session;
    }

    /**
     * 处理查询结果，其中结果是很多条的
     *
     * @param result 查询结果
     * @return 节点列表
     */
    private LinkedList<Node> processResult(Result result) {
        LinkedList<Node> nodes = new LinkedList<Node>();
        while (result.hasNext()) {
            Record record = result.next();
            Value n = record.get(0);
            NodeType nodeType = Node.nodeTypeMap.get(n.asNode().labels().iterator().next());
            Node node = new Node(nodeType, (String) record.fields().get(0).value().asMap().get("name"), n.asNode().id());
            nodes.add(node);
        }
        return nodes;
    }

    /**
     * 处理单个查询结果，转为node
     *
     * @param result 查询结果
     * @return 节点
     */
    private Node processSingleResult(Result result) {
        if (!result.hasNext()) {
            return null;
        } else {
            Record record = result.next();
            Value n = record.get(0);
            NodeType nodeType = Node.nodeTypeMap.get(n.asNode().labels().iterator().next());
            return new Node(nodeType, (String) record.fields().get(0).value().asMap().get("name"), n.asNode().id());
        }
    }

    /**
     * 创建一个节点，其中节点的id属性会被忽略掉，neo4j会自动生成
     *
     * @param node 创建的节点
     * @return 创建好的node对象
     */
    public Node createNode(Node node) {
        return session.writeTransaction(tx -> {
            String query = "CREATE (n:" + node.getLabel() + " {name: \"" + node.getName() + "\"}) RETURN n";
            System.out.println(query);
            Result result = tx.run(query);
            return processSingleResult(result);
        });
    }

    /**
     * 返回数据库中所有节点
     *
     * @return 节点列表
     */
    public LinkedList<Node> getNodes() {
        return session.readTransaction(tx -> {
            Result result = tx.run("MATCH (a) RETURN a");
            LinkedList<Node> nodes = processResult(result);
            return nodes;
        });
    }

    /**
     * 通过name查找节点
     *
     * @param name name
     * @return 节点列表
     */
    public LinkedList<Node> getNodesByName(String name) {
        return session.readTransaction(tx -> {
            Result result = tx.run("MATCH (a) WHERE a.name='" + name + "' RETURN a");
            return processResult(result);
        });
    }

    /**
     * 通过label 查找节点
     *
     * @param type label
     * @return 节点列表
     */
    public LinkedList<Node> getNodesByLabel(NodeType type) {
        return session.readTransaction(tx -> {
            Result result = tx.run("MATCH (a:" + type.getLabel() + ")  RETURN a");
            return processResult(result);
        });
    }

    /**
     * 通过name和label查找节点
     *
     * @param name name
     * @param type label
     * @return 节点列表
     */
    public LinkedList<Node> getNodesByNameAndType(String name, NodeType type) {
        return session.readTransaction(tx -> {
            Result result = tx.run("MATCH (a:" + type.getLabel() + ") WHERE a.name='" + name + "' RETURN a");
            return processResult(result);
        });
    }

    /**
     * 通过id查找节点
     * 如果没有，返回一个null
     *
     * @param id id
     * @return 节点
     */
    public Node getNodeById(Long id) {
        Result result = session.run("MATCH (a) WHERE id(a)=" + id + " RETURN a");
        return processSingleResult(result);
    }

    /**
     * 通过id更新节点
     * 如果没有这个id的节点，则会返回一个null
     *
     * @param id      id
     * @param newNode 新节点
     * @return 新节点
     */
    public Node updateNodeById(Long id, Node newNode) {
        return session.writeTransaction(tx -> {
            Node oldNode = processSingleResult(tx.run("MATCH (a) WHERE id(a)=" + id + " RETURN a"));
            if (oldNode == null) {
                return null;
            }
            tx.run("MATCH (a) WHERE id(a)=" + id + " SET a.name='" + newNode.name + "' RETURN a");
            tx.run("MATCH (n) WHERE id(n)=" + id + " REMOVE n:" + oldNode.label + " SET n:" + newNode.label + " RETURN n");
            newNode.setId(oldNode.getId());
            return newNode;
        });
    }


    /**
     * 通过id删除节点
     * 如果没有这个节点，会返回false
     *
     * @param id id
     * @return 是否成功
     */
    public boolean deleteNodeById(Long id) {
        return session.writeTransaction(tx -> {
            Node node = processSingleResult(tx.run("MATCH (a) WHERE id(a)=" + id + " RETURN a"));
            if (node == null) return false;
            try {
                tx.run("MATCH (a) WHERE id(a)=" + id + " DELETE a");
                return true;
            } catch (Exception e) {
                return false;
            }
        });
    }

}
